package com.stars.distributed.schedule.starter;

import com.stars.distributed.schedule.bean.DbScheduleServer;
import com.stars.distributed.schedule.core.DistributedScheduleManager;
import com.stars.distributed.schedule.factory.DbScheduleSqlSessionFactory;
import com.stars.distributed.schedule.handler.DbScheduleHandlerMappingRegister;
import com.stars.distributed.schedule.service.DistributedScheduleService;
import com.stars.distributed.schedule.repository.DbScheduleRepository;
import com.stars.distributed.schedule.compatibility.QuartzCompatibility;
import com.stars.distributed.schedule.util.ApplicationContextHolder;
import com.stars.distributed.schedule.util.DistributedSchedulePropertiesUtil;
import com.stars.distributed.schedule.util.DistributedSchedulePackageUtil;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * 分布式调度框架启动类：
 * 1.查找本地配置文件并封装分布式调度框架本地配置对象
 * 2.判断分布式调度框架是否激活，若没有激活则不启动分布式调度框架，若激活则启动分布式调度框架（PS：启动分布式调度框架不代表调度器打开）
 *
 * @author guoguifang
 */
public class DistributedScheduleStarter implements ApplicationContextAware {

    private static final Logger logger = LoggerFactory.getLogger(DistributedScheduleStarter.class);

    private static final Starter STARTER = new Starter();

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        ApplicationContextHolder.setApplicationContext(applicationContext);
        DistributedScheduleStarter.STARTER.start();
    }

    /**
     * 关闭分布式调度框架
     */
    public void stop() {
        DistributedScheduleStarter.STARTER.stop();
    }

    private static class Starter {

        private DbScheduleServer localDbScheduleServerConfig;

        private boolean started;

        private synchronized void start() {

            // 检查是否已经启动成功
            if (this.started) {
                if (logger.isDebugEnabled()) {
                    logger.debug("The distributed schedule framework is already started!");
                }
                return;
            }

            if (this.localDbScheduleServerConfig == null) {
                // 检查分布式调度框架是否激活
                if (logger.isDebugEnabled()) {
                    logger.debug("Ready to check whether the distributed schedule framework is enabled...");
                }
                this.localDbScheduleServerConfig = DistributedSchedulePropertiesUtil.encapsulateLocalDistributedScheduleServerConfig();
            }

            // 如果本地配置文件里为已激活，则立即启动分布式调度框架，若未激活则不启动
            if (!this.localDbScheduleServerConfig.isEnabled()) {
                logger.warn("The distributed schedule framework is disabled, if need to enable, please config [distributed.schedule.enabled=true] in the properties or yaml file!");
                return;
            }

            if (logger.isInfoEnabled()) {
                logger.info("The distributed schedule framework is enabled, if need to disabled, please config [distributed.schedule.enabled=false] in the properties or yaml file!");
            }

            // 启动框架，如果启动失败则关闭服务
            try {
                // 当分布式调度框架激活的时候需要关闭quartz的自动启动功能
                QuartzCompatibility.setAutoStartup(false);
                if (logger.isInfoEnabled()) {
                    logger.info("========================= The distributed schedule framework is ready to start... =========================");
                }

                // 若分布式调度框架已激活则初始化分布式调度框架的Repository
                initRepository();

                // 初始化分布式调度框架的相关表以及相关数据
                DistributedScheduleService.getInstance().initTable();

                // 注册分布式调度框架UrlHandlerMapping
                DbScheduleHandlerMappingRegister.register();

                // 激活分布式调度框架的控制者并启动
                DistributedScheduleManager distributedScheduleManager = DistributedScheduleManager.getSingleInstance();
                distributedScheduleManager.setLocalDbScheduleServerConfig(this.localDbScheduleServerConfig);
                distributedScheduleManager.enable();
                distributedScheduleManager.start();

                // 启动成功并记录日志
                this.started = true;
                if (logger.isInfoEnabled()) {
                    logger.info("========================= The distributed schedule framework start-up success =========================");
                }
            } catch (Exception e) {
                logger.error("========================= The distributed schedule framework start-up failure =========================", e);
                System.exit(1);
            }
        }

        private synchronized void stop() {
            // 检查是否已经启动成功
            if (!this.started) {
                if (logger.isDebugEnabled()) {
                    logger.debug("The distributed schedule framework is not started!");
                }
                return;
            }

            DistributedScheduleManager.getSingleInstance().stopSchedule();
        }

        /**
         * 扫描Repository Package下所有DAO接口
         */
        private void initRepository() {
            DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) ApplicationContextHolder.getApplicationContext().getAutowireCapableBeanFactory();
            defaultListableBeanFactory.registerSingleton("dbScheduleSqlSessionFactory", DbScheduleSqlSessionFactory.getSqlSessionFactory());
            MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
            mapperScannerConfigurer.setSqlSessionFactoryBeanName("dbScheduleSqlSessionFactory");
            mapperScannerConfigurer.setBasePackage(DistributedSchedulePackageUtil.getRepositoryPackageName());
            mapperScannerConfigurer.setAnnotationClass(DbScheduleRepository.class);
            defaultListableBeanFactory.registerSingleton(DistributedSchedulePackageUtil.getRootPackageName() + ".mapperScannerConfigurer", mapperScannerConfigurer);
            mapperScannerConfigurer.postProcessBeanDefinitionRegistry(defaultListableBeanFactory);
        }

        private Starter() {}
    }

}
